/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package AnalisadorLexico;

import Hash.Metodos;
import TabelaDeSimbolos.nodoEncadeado;
import static TabelaDeSimbolos.classeTabelaSimbolos.tabelaSimbolos;
import java.io.*;

/**
 *
 * @author 341232
 */
public class Lexico {

    int S = 0;
    BufferedReader arq;
    boolean lexemaDevolvido = false;
    char tokenCorrente;
    int numLinhas = 1;
    boolean fimArquivo = false;
    String lexema = "";
    public Metodos metodo;
    public static nodoEncadeado nodoRegistrado;

    public void checarCaractere(char c) {

//        Os caracteres permitidos em um arquivo fonte são as letras,
//        dígitos, espaço, ponto, vírgula, ponto-e-vírgula, dois-pontos,
//        parênteses, colchetes, chaves, mais, menos, aspas, apóstrofo,
//        barra, cifrão, exclamação, interrogação, maior, menor e igual,
//        além da quebra de linha (bytes 0Dh e 0Ah). Qualquer outro caractere
//        é considerado inválido, não podendo aparecer nem em comentários. 

        if (!Character.isLetterOrDigit(c) && c != ' ' && c != '.' && (int) c != 9
                && c != ',' && c != ';' && c != ':' && c != '(' && c != ')'
                && c != '[' && c != ']' && c != '{' && c != '}' && c != '+'
                && c != '-' && c != '"' && (int) c != 39 && c != '/' && c != '$'
                && c != '!' && c != '?' && c != '>' && c != '<'
                && c != '=' && (byte) c != 13 && (byte) c != 10 && c != '*' && (int) c != 65535) {
            mensagemErro(CodigoErros.caractereInvalido.getCodigoErro(), lexema);
        }
    }

    public void Lexico(String arquivo) throws IOException {
        //estados
        arq = new BufferedReader(new FileReader(arquivo));
        metodo = new Metodos();

    }

    public void lerChar() throws IOException {
        if (!lexemaDevolvido) {
            tokenCorrente = (char) arq.read();
            checarCaractere(tokenCorrente);
        } else {
            lexemaDevolvido = false;
        }
        if (tokenCorrente == '\n') {
            numLinhas++;
        }
        if ((int) tokenCorrente == 65535 && (int) tokenCorrente != 13) {
            fimArquivo = true;
        }
    }

    public String formataLinhas(String linhaErro) {
        if (numLinhas < 9) {
            linhaErro = "0" + numLinhas;
        } else {
            linhaErro = "" + numLinhas;
        }
        return linhaErro;
    }

    public void mensagemErro(int tipoErro, String lexema) {
        int tipo = 0;

        nodoEncadeado nodoErro;

        nodoErro = metodo.pesquisa(lexema);




        if (!lexema.equals("")) {
            tipo = (int) lexema.charAt(0);
        }

        if (nodoErro == null) {
            nodoErro = new nodoEncadeado((byte) 0, lexema);
        }

        if ((int) tokenCorrente != 65535) {
            lexema += tokenCorrente;
        }
        String linhaErro = "";
        linhaErro = formataLinhas(linhaErro);

        if (tipoErro == CodigoErros.caractereInvalido.getCodigoErro()) {

            System.out.println(linhaErro + ":caractere invalido.");
        } else if (tipoErro == CodigoErros.lexemaNaoIdentificado.getCodigoErro()) {

            System.out.println(linhaErro + ":lexema nao identificado. [" + lexema + "]");
        } else if (tipoErro == CodigoErros.fimDeArquivoNaoEsperado.getCodigoErro()) {

            System.out.println(linhaErro + ":fim de arquivo nao esperado.");
            
            //Erros semanticos            
            
        } else if (tipoErro == CodigoErros.tokenNaoEsperado.getCodigoErro()) {
            System.out.println(linhaErro + ":token nao esperado. [" + nodoErro.getLexema() + "]");
        } else if (tipoErro == CodigoErros.classeIncompativel.getCodigoErro()) {

            System.out.println(linhaErro + ":classe de identificador incompatível. [" + nodoErro.getLexema() + "]");
        } else if (tipoErro == CodigoErros.identificadorNaoDeclarado.getCodigoErro()) {

            System.out.println(linhaErro + ":identificador nao declarado. [" + nodoErro.getLexema() + "]");
        } else if (tipoErro == CodigoErros.identificadorJaDeclarado.getCodigoErro()) {
            System.out.println(linhaErro + ":identificador ja declarado. [" + nodoErro.getLexema() + "]");
        } else if (tipoErro == CodigoErros.tiposIncompativeis.getCodigoErro()) {
            System.out.println(linhaErro + ":tipos incompatíveis. [" + nodoErro.getLexema() + "]");
        } else {
            System.out.println("Erro desconhecido");
        }


        System.exit(0);
    }

    public nodoEncadeado AnalisaLexico() throws IOException {
        lerChar();

        do {
            switch (S) {
                case 0:
                    estado0(tokenCorrente);
                    break;
                case 1:
                    estado1(tokenCorrente);
                    break;
                case 3:
                    estado3(tokenCorrente);
                    break;
                case 4:
                    estado4(tokenCorrente);
                    break;
                case 5:
                    estado5(tokenCorrente);
                    break;
                case 6:
                    estado6(tokenCorrente);
                    break;
                case 7:
                    estado7(tokenCorrente);
                    break;
                case 8:
                    estado8(tokenCorrente);
                    break;
                case 9:
                    estado9(tokenCorrente);
                    break;
                case 10:
                    estado10(tokenCorrente);
                    break;
                case 11:
                    estado11(tokenCorrente);
                    break;
                case 12:
                    estado12(tokenCorrente);
                    break;
                case 13:
                    estado13(tokenCorrente);
                    break;
                case 14:
                    estado14(tokenCorrente);
                    break;
                case 15:
                    estado15(tokenCorrente);
                    break;
                case 16:
                    estado16(tokenCorrente);
                    break;
                case 17:
                    estado17(tokenCorrente);
                    break;
                case 18:
                    //estado18(tokenCorrente);
                    break;
                case 19:
                    estado19(tokenCorrente);
                    break;
                case 20:
                    estado20(tokenCorrente);
                    break;
                case 21:
                    estado21(tokenCorrente);
                    break;


            }
        } while (S != 2);
        S = 0;
        lexema = "";

        return nodoRegistrado;
    }// FIM ANALISADOR LEXICO

    public void estado0(char c) throws IOException {
        if (Character.isLetter(c)) {
            lexema += c;
            lerChar();
            S = 1;
        } else if (c == '>' || c == '=') {
            lexema += c;
            lerChar();
            S = 5;//se eu ler > ou = vai pro 5
        } else if (c == '<') {
            lexema += c;
            lerChar();
            S = 4; //Se eu ler menor vai pro 4
        } else if (Character.isDigit(c)) {
            lexema += c;
            lerChar();
            S = 6;
        } else if (c == '"') {
            lexema += c;
            lerChar();
            S = 2;
        } else if (c == '/') {
            lexema += c;
            lerChar();
            S = 2;
        } else if (c == '{') {
            lexema += c;
            lerChar();
            S = 3; //SE EU LER COMENTARIO IR PARA ESTADO 3
        } else if (c == '.') {
            lexema += c;
            lerChar();
            //S = 10; //SE EU LER COMENTARIO IR PARA ESTADO 10
            S = 19;
        } else if (c == ' ' || (int) c == '\n' || (int) c == 9) { //|| (int) c == 13;
            lexema = "";
            lerChar();
            S = 0;
        } else if (c == '$') {
            lerChar();
            S = 17;
        } else if ((int) c == 13) {
            lexema = "";
            lerChar();
            S = 16;

        } else if ((int) c == 65535) {
            lexema += c;
            //nodoRegistrado = metodo.pesquisa(lexema);
            lexema += c;
            lerChar();
            S = 2;
            //Mandava pra aceitacao S = 2
        } else {
            lexema += c; //Estava pegando o ponto e virgula
            //metodo.insercao((byte)-1, lexema,"");
            // nodoRegistrado = new nodoEncadeado((byte)23,lexema);

            if (metodo.pesquisa(lexema) == null) {
                metodo.insercao((byte) -3, lexema, "");
                nodoRegistrado = new nodoEncadeado((byte) -3, lexema);
            } else {
                nodoRegistrado = metodo.pesquisa(lexema);
            }

            S = 2;
        }
    }// FIM ESTADO 0

    public void estado20(char c) throws IOException { // Novo
        if (Character.isDigit(c)) {
            lerChar();
            S = 12;
        } else {
            lerChar();
            lexemaDevolvido = true;
            if (metodo.pesquisa(lexema) == null) {
                metodo.insercao((byte) -1, lexema, "");
                nodoRegistrado = new nodoEncadeado((byte) -1, lexema);
            } else {
                nodoRegistrado = metodo.pesquisa(lexema);
            }
            S = 2;
        }
    }// FIM ESTADO 20

    public void estado19(char c) throws IOException { // Novo
        if (Character.isDigit(c)) {
            lerChar();
            S = 20;
        } else {
            mensagemErro(CodigoErros.tokenNaoEsperado.getCodigoErro(), lexema);
        }

    }// FIM ESTADO 19

    public void estado17(char c) throws IOException { // Novo
        if (c == '\r') {
            lerChar();
            lerChar();
            if (tokenCorrente != '\r') {
                S = 0;
            } else {
                mensagemErro(CodigoErros.tokenNaoEsperado.getCodigoErro(), lexema);
            }
        } else if (tokenCorrente == '{') {
            S = 3;
        }
    }// FIM ESTADO 16

    public void estado16(char c) throws IOException { // Novo
        if (c == '\n') {
            lexema += c;
            if (metodo.pesquisa(lexema) == null) {
                metodo.insercao((byte) 46, lexema, "");
                nodoRegistrado = new nodoEncadeado((byte) -1, lexema);
            } else {
                nodoRegistrado = metodo.pesquisa(lexema);
            }
            S = 2;
        }
    }// FIM ESTADO 16

    public void estado1(char c) throws IOException {
        if (Character.isLetter(c) || Character.isDigit(c)) {
            lexema += c;
            lerChar();
        } else {
            lexemaDevolvido = true;

            if (metodo.pesquisa(lexema) == null) {
                metodo.insercao((byte) -1, lexema, "");
                nodoRegistrado = new nodoEncadeado((byte) -1, lexema);
            } else {
                nodoRegistrado = metodo.pesquisa(lexema);
            }
            S = 2;
        }
    }// FIM ESTADO 1

    public void estado15(char c) throws IOException {
        if (c == '{') {
            lexema = "";
            lerChar();
            S = 3;
        } else if (c == ' ') {
            lexema = "";
            lerChar();
            S = 15;
        } else if (c == '\n') {
            lexema = "";
            lerChar();
            S = 0;
        }
    }// FIM ESTADO 1

    public void estado5(char c) { //ESTADO 5
        if (c == '=') {
            lexema += c;
            if (metodo.pesquisa(lexema) == null) {
                metodo.insercao((byte) -1, lexema, "");
                nodoRegistrado = new nodoEncadeado((byte) -1, lexema);
            } else {
                nodoRegistrado = metodo.pesquisa(lexema);
            }
            S = 2;
        } else {
            lexemaDevolvido = true;
            if (metodo.pesquisa(lexema) == null) {
                metodo.insercao((byte) -1, lexema, "");
                nodoRegistrado = new nodoEncadeado((byte) -1, lexema);
            } else {
                nodoRegistrado = metodo.pesquisa(lexema);
            }
            S = 2;
        }
    }// FIM ESTADO 5

    public void estado4(char c) { //ESTADO 4
        if (c == '=') {
            lexema += c;
            if (metodo.pesquisa(lexema) == null) {
                metodo.insercao((byte) -1, lexema, "");
                nodoRegistrado = new nodoEncadeado((byte) -1, lexema);
            } else {
                nodoRegistrado = metodo.pesquisa(lexema);
            }
            S = 2;
        } else if (c == '>') {
            lexema += c;
            if (metodo.pesquisa(lexema) == null) {
                metodo.insercao((byte) -1, lexema, "");
                nodoRegistrado = new nodoEncadeado((byte) -1, lexema);
            } else {
                nodoRegistrado = metodo.pesquisa(lexema);
            }
            S = 2;
        } else {
            lexemaDevolvido = true;
            if (metodo.pesquisa(lexema) == null) {
                metodo.insercao((byte) -1, lexema, "");
                nodoRegistrado = new nodoEncadeado((byte) -1, lexema);
            } else {
                nodoRegistrado = metodo.pesquisa(lexema);
            }
            S = 2;
        }
    }// FIM ESTADO 4

    public void estado6(char c) throws IOException { //ESTADO 6
        if (Character.isDigit(c)) {
            lexema += c;
            lerChar();
            if (Character.isLetter(tokenCorrente)) { // Mudei de alphabetic para letter por causa do netbeans do trabalho
                mensagemErro(CodigoErros.lexemaNaoIdentificado.getCodigoErro(), lexema);
            }
            S = 7;
        } else if (c == '.') {
            lexema += c;
            lerChar();
            S = 10;
        } else if (Character.isLetter(tokenCorrente)) { // Mudei de alphabetic para letter por causa do netbeans do trabalho
            mensagemErro(CodigoErros.lexemaNaoIdentificado.getCodigoErro(), lexema);
        } else {
            lexemaDevolvido = true;

            if (metodo.pesquisa(lexema) == null) {
                metodo.insercao((byte) -2, lexema, "digito");
                nodoRegistrado = new nodoEncadeado((byte) -2, lexema);

            } else {
                nodoRegistrado = metodo.pesquisa(lexema);
            }
            S = 2;
        }

    }// FIM ESTADO 6

    public void estado7(char c) throws IOException { //ESTADO 6
        if (Character.isDigit(c)) {
            lexema += c;
            lerChar();
            S = 8;
        } else if (c == '.') {
            lexema += c;
            lerChar();
            S = 10;
        } else {
            lexemaDevolvido = true;
            if (metodo.pesquisa(lexema) == null) {
                metodo.insercao((byte) -2, lexema, "digito");
                nodoRegistrado = new nodoEncadeado((byte) -2, lexema);

            } else {
                nodoRegistrado = metodo.pesquisa(lexema);
            }
            S = 2;
        }
    }// FIM ESTADO 7

    public void estado8(char c) throws IOException { //ESTADO 6
        if (Character.isDigit(c)) {
            lexema += c;
            lerChar();
            S = 9;
        } else if (c == '.') {
            lexema += c;
            lerChar();
            S = 10;
        } else {
            lexemaDevolvido = true;
            if (metodo.pesquisa(lexema) == null) {
                metodo.insercao((byte) -2, lexema, "digito");
                nodoRegistrado = new nodoEncadeado((byte) -2, lexema);

            } else {
                nodoRegistrado = metodo.pesquisa(lexema);
            }
            S = 2;
        }
    }// FIM ESTADO 8

    public void estado9(char c) throws IOException { //ESTADO 6
        if (Character.isDigit(c)) {
            lexema += c;
            lerChar();
            S = 14;
        } else if (c == '.') {
            lexema += c;
            lerChar();
            S = 10;
        } else {
            lexemaDevolvido = true;
            if (metodo.pesquisa(lexema) == null) {
                metodo.insercao((byte) -2, lexema, "digito");
                nodoRegistrado = new nodoEncadeado((byte) -2, lexema);

            } else {
                nodoRegistrado = metodo.pesquisa(lexema);
            }
            S = 2;
        }
    }// FIM ESTADO 9

    public void estado10(char c) throws IOException {
        if (Character.isDigit(c)) {
            lexema += c;
            lerChar();
            S = 11;
        } else {
            lexemaDevolvido = true;
            if (metodo.pesquisa(lexema) == null) {
                metodo.insercao((byte) -2, lexema, "digito");
                nodoRegistrado = new nodoEncadeado((byte) -2, lexema);

            } else {
                nodoRegistrado = metodo.pesquisa(lexema);
            }
            S = 2;
        }
    }

    public void estado11(char c) throws IOException {
        if (Character.isDigit(c)) {
            lexema += c;
            lerChar();
            S = 12;
        } else {
            lexemaDevolvido = true;
            if (metodo.pesquisa(lexema) == null) {
                metodo.insercao((byte) -2, lexema, "digito");
                nodoRegistrado = new nodoEncadeado((byte) -2, lexema);

            } else {
                nodoRegistrado = metodo.pesquisa(lexema);
            }
            S = 2;
        }
    }

    public void estado12(char c) throws IOException {
        if (Character.isDigit(c)) {
            lexema += c;
            lerChar();
            S = 13;
        } else {
            lexemaDevolvido = true;
            if (metodo.pesquisa(lexema) == null) {
                metodo.insercao((byte) -2, lexema, "digito");
                nodoRegistrado = new nodoEncadeado((byte) -2, lexema);

            } else {
                nodoRegistrado = metodo.pesquisa(lexema);
            }
            S = 2;
        }
    }

    public void estado13(char c) throws IOException {
        if (Character.isDigit(c)) {
            lexema += c;
            lerChar();
            S = 21;
        } else {
            lexemaDevolvido = true;
            if (metodo.pesquisa(lexema) == null) {
                metodo.insercao((byte) -2, lexema, "digito");
                nodoRegistrado = new nodoEncadeado((byte) -2, lexema);

            } else {
                nodoRegistrado = metodo.pesquisa(lexema);
            }
            S = 2;
        }
    }

    public void estado21(char c) throws IOException {
        if (Character.isDigit(c) || c == '.') {
            mensagemErro(CodigoErros.tokenNaoEsperado.getCodigoErro(), c + "");
        } else {
            lexemaDevolvido = true;
            if (metodo.pesquisa(lexema) == null) {
                metodo.insercao((byte) -2, lexema, "digito");
                nodoRegistrado = new nodoEncadeado((byte) -2, lexema);

            } else {
                nodoRegistrado = metodo.pesquisa(lexema);
            }
            S = 2;
        }
    }

    public void estado14(char c) throws IOException {
        if (Character.isDigit(c)) {
            lexema += c;
            lerChar();
            S = 14;
        } else {
            lexemaDevolvido = true;
            if (metodo.pesquisa(lexema) == null) {
                metodo.insercao((byte) -2, lexema, "digito");
                nodoRegistrado = new nodoEncadeado((byte) -2, lexema);

            } else {
                nodoRegistrado = metodo.pesquisa(lexema);
            }
            S = 2;
        }
    }

    public void estado3(char c) throws IOException { // Novo
        if (c != '}' && (int) c != 65535) {
            lexema = "";
            lerChar();
            S = 3;
        } else if ((int) c == 65535) {
            mensagemErro(CodigoErros.fimDeArquivoNaoEsperado.getCodigoErro(), "");
        } else if (c == '}') {
            //lexema += c;
            lexema = "";
            lerChar();
//            if (tokenCorrente == '\n') {
//                lerChar();
//                lerChar();
//
//            }
//            else if(tokenCorrente == '\r') {
//            lerChar();
//            }
            S = 0;

        }
    }// FIM ESTADO 3
}
